package com.haiyou.data.common.persister.mysql.dao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang3.Validate;

import com.haiyou.common.entity.Entity;
import com.haiyou.common.util.collect.CollectionUtils;


public interface BaseEntityDao<Id extends Serializable & Comparable<Id>, E extends Entity<Id>> extends BaseDao {

	/** id的class类型 */
	Class<Id> getIdClass();

	/** entity的class类型 */
	Class<E> getEntityClass();

	/** 总条数 */
	int count();

	/** 总条数 */
	int countByCondition(String condition);

	/** 主键的最大值 */
	Id maxPk();

	/** 插入一条记录 */
	boolean insert(E entity);

	/** 批量插入 */
	void insert(Iterable<? extends E> iterable);

	/** 如果不存在就插入 */
	boolean insertIfNotExists(E entity);

	/** 如果不存在就插入 */
	void insertIfNotExists(Iterable<? extends E> iterable);

	/** 如果存在先删除再插入 */
	boolean replace(E entity);

	/** 如果存在先删除再插入 */
	void replace(Iterable<? extends E> iterable);

	/** 插入一条记录，如果存在执行更新 */
	boolean insertOrUpdate(E entity);

	/** 插入一条记录，如果存在执行更新,排除自增Id */
	boolean insertOrUpdateExcludeAutoId(E entity);

	/** 批量插入，如果已经存在执行更新 */
	void insertOrUpdate(Iterable<? extends E> iterable);

	/** 插入一条记录并返回自增得到的主键 */
	Integer return_generated_Id(E entity);

	/** 删除一条记录 */
	boolean delete(Id id);

	/** 删除一批 */
	void delete(Iterable<? extends Id> ids);

	/** 按条件删除 */
	void deleteByCondition(String condition);

	/**
	 * <pre>
	 * 慎用
	 * </pre>
	 * 
	 * 逐条删除 (速度较慢),identity 依旧是接着被删除的最近的那一条记录ID加1后进行记录。如果只需删除表中的部分记录，只能使用 DELETE语句配合
	 * where条件
	 */
	void delete();

	/**
	 * <pre>
	 * 慎用
	 * </pre>
	 * 
	 * 整体删除 (速度较快),不激活trigger (触发器)，但是会重置Identity
	 * (标识列、自增字段)，相当于自增列会被置为初始值，又重新从1开始记录，而不是接着原来的 ID数
	 */
	void truncate();

	/** 全量更新一条记录 */
	boolean update(E entity);

	/** 批量全量更新 */
	void update(Iterable<? extends E> iterable);

	/** 是否存在主键记录 */
	boolean contains(Id id);

	/** 按主键查询一个 */
	E query(Id id);

	/** 按主键查询一批 */
	List<E> queryBatch(Iterable<? extends Id> ids);

	/** 按条件查询 */
	List<E> queryByCondition(String condition);

	/** 查询全部主键 */
	List<Id> queryIds();

	/** 查询全部 */
	List<E> queryAll();

	/**
	 * 根据指定某个字段的值查询
	 * 
	 * @param column
	 * @param value
	 * @return 一个或多个结果
	 */
	default List<E> queryBy(String column, Object value) {
		return queryByCondition(String.format("`%s`='%s'", column, value));
	}

	/**
	 * 根据指定某个字段的值查询
	 * 
	 * @param column 唯一索引
	 * @param value
	 * @return 只有一个结果或者没有
	 */
	default E queryByUniqueIndex(String column, Object value) {
		List<E> list = queryBy(column, value);
		Validate.isTrue(list.size() <= 1);
		return list.isEmpty() ? null : CollectionUtils.peekFirst(list);
	}

	/**
	 * 根据组合条件查询 a=1 and b=2 and c=3
	 * 
	 * @param options
	 * @return 一个或多个结果
	 */
	default List<E> queryByOptions(Map<String, Object> options) {
		return queryByCondition(conditions(options, "and"));
	}

	/**
	 * 根据组合条件模糊查询 a=1 or b=2 or c=3
	 * 
	 * @param options
	 * @return 一个或多个结果
	 */
	default List<E> queryByFuzzy(Map<String, Object> options) {
		return queryByCondition(conditions(options, "or"));
	}

	/**
	 * 使用全文索引查询 @see {@link IndexPolicy.FULLTEXT}
	 * 
	 * 
	 * @param columns        全文索引的列名，可以支持联合索引
	 * @param params         条件参数的值
	 * @param useBooleanMode 是否使用布尔全文索引查询
	 * @return
	 */
	List<E> queryByFullText(String[] columns, Object[] params, boolean useBooleanMode);

	/**
	 * 拼接多参数条件
	 * 
	 * @param options
	 * @param option  and/or
	 * @return
	 */
	default String conditions(Map<String, Object> options, String option) {
		Validate.isTrue(option.toLowerCase().equals("and") || option.toLowerCase().equals("or"));
		StringBuilder builder = new StringBuilder();
		int i = 0;
		for (Entry<String, Object> entry : options.entrySet()) {
			String column = entry.getKey();
			Object value = entry.getValue();
			builder.append('`').append(column).append('`').append('=').append('\'').append(value).append('\'');
			if (i++ < options.size() - 1)
				builder.append(' ').append(option).append(' ');
		}
		return builder.toString();
	}

}
